package edu.umn.ftpmaster;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Master {
	
	private List <Event> events = new ArrayList<Event>();
	private int EventCount = 0;
	private int firstPort = 2200;
	private int masterPort = 2199;
	private ServerSocket master=null;
	
	public Master(){
		try {
			master = new ServerSocket(masterPort);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/**
	 * start the master
	 */
	public void masterStart()
	{
		
		while(true)
		{
			System.out.println("master started");
			try {
				new dealwithit(master.accept()).start();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	/**
	 * thread that deals with the incoming message
	 * @author Chonglei
	 *
	 */
	private class dealwithit extends Thread{
		private Socket socket = null;
		
		private dealwithit(Socket socket1){
			super("dealwithit");
			this.socket = socket1;
		}
		
		public void run() {
			try {
				
				System.out.println("received a connection");
				
				ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
				ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
				Object data =null;
				
				while(socket.isConnected()){
					if((data = ois.readObject()) != null)
					{
					String option = ((Command)data).getOption();
					if(option.equals("connect")){//first come
						Location ll = ((Command)data).getLocation();
						List<Event> usefulEvents=ListEvent(ll);
						//to do
						//send back the available events by location
						//oos.writeObject(usefulEvents);
						
						System.out.println("received new request");
					}else if(option.equals("new")){//create a new event
						Location ll = ((Command)data).getLocation();
						String eventName = ((Command)data).getName();
						int radius = Integer.parseInt(((Command)data).getMessage().trim());
						
						InetAddress addr = socket.getInetAddress();
						Event newEvent=AddEvent(ll,eventName);
						newEvent.setScope(radius);
						
						Account account=AddNewUser(newEvent,addr);
						
						//create response
						Command cc = new Command("account",null,null,String.valueOf(newEvent.port)+","+account.username+","+account.password);
						//send response
						oos.writeObject(cc);
						
						System.out.println("done with new");
					}else if(option.equals("join")){//join the one of the current event
						String eventName = ((Command)data).getName();
						Event event = findEventByName(eventName);
						
						//add new account and new client
						InetAddress addr = socket.getInetAddress();
						Account account=AddNewUser(event,addr);
						
						//create response
						Command cc = new Command("account",null,null,String.valueOf(event.port)+","+account.username+","+account.password);
						//send response
						oos.writeObject(cc);
					}
					else if(option.equals("done")){
						break;
					}
					}
				}
				
			} catch (IOException e) {
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
			
		}
	}
	/**
	 * add a new event 
	 */
	public Event AddEvent(Location ll, String eventName)
	{
		String dirName = "event"+EventCount;	
		Event event = new Event(ll,eventName,dirName,firstPort+EventCount);
		EventCount++;
		events.add(event);
		return event;
	}
	/**
	 * list the available events based on the incoming location
	 */
	public List<Event> ListEvent(Location ll)
	{
		//to do
		//list the available events and return to  the user
		List<Event> currentEvents = new ArrayList<Event>();
		for(Iterator<Event> it = events.iterator();it.hasNext();){
			Event currentEvent = it.next();
			if(util.distance(currentEvent.locl, ll)<it.next().radius){
				currentEvents.add(currentEvent);
			}
		}
		return currentEvents;
	}
	
	/**
	 * add a new user into the corresponding event
	 * @param event: the event that will add a new user
	 * @return : the generated account
	 */
	public Account AddNewUser(Event event,InetAddress addr)
	{
		Account account = new Account();
		account.username = event.getName()+event.count;					//username
		event.count++;
		account.password = String.valueOf(System.currentTimeMillis());	//password
		
		//add a new client
		event.addClient(account,addr);
		//add a new account to the FTP server
		event.server.addAccount(account);
		
		//to do
		//send the generated account to the mobile user
		return account;
	}
	private Event findEventByName(String name){
		  for(Iterator<Event>it= events.iterator();it.hasNext();)    {   
		       Event event =it.next();
		       if(event.getName().equals(name)){
		    	   return event;
		       }
		   }
		  return null;
	}
	
}
